\documentclass[supercite]{Experimental_Report}

\title{~~~~~~Python大数据与人工智能实验~~~~~~}
\author{}
\school{计算机科学与技术学院}
\classnum{}
\stunum{}
\instructor{邹逸雄}
\date{2022年11月17日}

\usepackage{algorithm, multirow}
\usepackage{algpseudocode}
\usepackage{amsthm}
\usepackage{amsmath}
\usepackage{framed}
\usepackage{mathtools}
\usepackage{subcaption}
\usepackage{xltxtra}
\usepackage{bm}
\usepackage{tikz}
%\usepackage{tikzscale}
\usepackage{pgfplots}
\usepackage{amssymb}

\pgfplotsset{compat=1.16}

\newcommand{\cfig}[3]{
  \begin{figure}[htb]
    \centering
    \includegraphics[width=#2\textwidth]{images/#1.tikz}
    \caption{#3}
    \label{fig:#1}
  \end{figure}
}

\newcommand{\sfig}[3]{
  \begin{subfigure}[b]{#2\textwidth}
    \includegraphics[width=\textwidth]{images/#1.tikz}
    \caption{#3}
    \label{fig:#1}
  \end{subfigure}
}

\newcommand{\xfig}[3]{
  \begin{figure}[htb]
    \centering
    #3
    \caption{#2}
    \label{fig:#1}
  \end{figure}
}

\newcommand{\rfig}[1]{\autoref{fig:#1}}
\newcommand{\ralg}[1]{\autoref{alg:#1}}
\newcommand{\rthm}[1]{\autoref{thm:#1}}
\newcommand{\rlem}[1]{\autoref{lem:#1}}
\newcommand{\reqn}[1]{\autoref{eqn:#1}}
\newcommand{\rtbl}[1]{\autoref{tbl:#1}}

\algnewcommand\Null{\textsc{null }}
\algnewcommand\algorithmicinput{\textbf{Input:}}
\algnewcommand\Input{\item[\algorithmicinput]}
\algnewcommand\algorithmicoutput{\textbf{Output:}}
\algnewcommand\Output{\item[\algorithmicoutput]}
\algnewcommand\algorithmicbreak{\textbf{break}}
\algnewcommand\Break{\algorithmicbreak}
\algnewcommand\algorithmiccontinue{\textbf{continue}}
\algnewcommand\Continue{\algorithmiccontinue}
\algnewcommand{\LeftCom}[1]{\State $\triangleright$ #1}

\newtheorem{thm}{定理}[section]
\newtheorem{lem}{引理}[section]

\colorlet{shadecolor}{black!15}

\theoremstyle{definition}
\newtheorem{alg}{算法}[section]

\def\thmautorefname~#1\null{定理~#1~\null}
\def\lemautorefname~#1\null{引理~#1~\null}
\def\algautorefname~#1\null{算法~#1~\null}

\begin{document}

\maketitle

\clearpage

\pagenumbering{Roman}

\tableofcontents[level=2]

\clearpage

\pagenumbering{arabic}

\section{实验目的和总述}

\subsection{问题背景}

自然语言处理(Natural Language Processing, NLP)是计算机科学领域与人工智能领域中的一个重要方向，
其研究能实现人与计算机之间使用自然语言进行有效通信的各种理论和方法。
作为NLP情感分析这一国内外研究热点的一大重要分支，NLP情感分类在当今信息过滤需求不断增加的情形下受到越来越多的关注，愈发重要。[1]
NLP情感分类所研究的对象是文本的主观因素，其根据文本所表达的含义和情感信息将文本划分成褒义贬义两种类型或多种类型，
是对文本作者倾向性和观点态度的划分，其在购物评论、电影评论等场景应用广泛。

早期的情感分类算法多采用传统的机器学习方法实现，如支持向量机（SVM）、朴素贝叶斯等方法，其对文本的表示多采用词袋模型。
这些方法普遍存在着缺乏语义信息等的缺点。近年来，卷积神经网络（CNN）、循环神经网络（RNN）等深度学习网络逐渐被应用于情感分类中，
大大推动了情感分类的发展。[2]本文采用基于神经网络的模型来解决情感分类问题。

本实验需要我们自行构建NLP情感分类程序，对烂番茄电影评论进行情感分类。
根据烂番茄电影评论的文本数据(数据整体由评论语句以及对应的情感标签组成),构建并训练模型，
实现对给定未知情感标签的评论能够给出合理的打分。

\subsection{程序结构}

为实现相应功能，整个程序主要由数据集预处理、网络构建、网络训练、网络测试4大部分构成。

在数据集预处理中，对数据进行\textbf{分割}，并进行\textbf{数据预处理}。
在网络构建模块中，我们构建了\textbf{3个不同神经网络模型}，设置了相应的网络参数和网络结构。
在网络训练中，统一调度前两个模块，构建Dataloader，选择损失函数、优化器等，进行三个网络的训练。
在网络测试中，运用模型进行分类求解，并以可视化的形式展示相应的网络参数和测试结果。

本程序支持\textbf{训练、测试结果图像的复现，测试的复现以及重新训练}。具体操作步骤请见根目录下的运行说明.md或运行说明.pdf。

\newpage
\section{数据集的处理}

为了对我们训练的网络的泛化能力进行评估，我们首先对原始数据进行\textbf{数据分割}。
对于分割后的每一个数据集，为了获得对数据的初步认识，我们进行了\textbf{数据预处理}，尝试寻找到数据集的一些典型特征。
数据集处理相关的代码是根目录下的data\_process.py文件中的DataSplit类。
通过数据处理，我们对数据集有了初步的判断和认知，这也为我们后续搭建网络，训练验证等提供了有效参考。

\subsection{数据分割}

为了评估模型的泛化能力，我们采用\textbf{3次留出法}进行测试。这要求我们随机地把原始数据分成3组，每组按9:1的比例分为训练集和验证集。

为了尽可能保证训练集和测试集分割之后能保持较好的随机性和完整性，我们使用sklearn库的train\_test\_split进行训练集和验证集的分割。
数据分割的函数是DataSplit类中的split\_data方法。
分割后的文件保存至根目录data文件夹下的data1,data2,data3三个文件夹。其中训练集和验证集的比例为0.9，0.1，
训练集保存为train.csv文件,测试集保存为valid.csv。

\subsection{数据预处理与分析}

完成分割后，我们开始对数据进行处理与分析。
首先，我们认为数据中不存在无效语句，故保留了所有语句。
其次，我们针对数据的特点，\textbf{以绘图的方式对数据集的重要特征进行图形化展示}。
我们对数据集中不同情感类别分布规律(1-5分别代表不同的评价类型)，词句长度分布规律进行了统计，使用的数据的样本为。原始数据集，第一个训练集以及三个测试集，具体结果如下所示：

\begin{figure}[H]
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/data_preprocess/raw_data/训练数据词句长度统计.pdf}
        \centerline{(1) 数据词句长度统计}
    \end{minipage}%
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/data_preprocess/raw_data/训练数据类别统计.pdf}
        \centerline{(2) 训练数据类别统计}
    \end{minipage}
    \caption{初始数据集特征统计图}\label{fig:figure}
\end{figure}

\begin{figure}[H]
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/data_preprocess/data1train/训练数据词句长度统计.pdf}
        \centerline{(1) 数据词句长度统计}
    \end{minipage}%
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/data_preprocess/data1train/训练数据类别统计.pdf}
        \centerline{(2) 训练数据类别统计}
    \end{minipage}
    \caption{训练数据集1特征统计图}\label{fig:figure2}
\end{figure}

\begin{figure}[H]
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/data_preprocess/data1valid/训练数据词句长度统计.pdf}
        \centerline{(1) 数据词句长度统计}
    \end{minipage}%
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/data_preprocess/data1valid/训练数据类别统计.pdf}
        \centerline{(2) 数据类别统计}
    \end{minipage}
    \caption{验证数据集1特征统计图}\label{fig:figure3}
\end{figure}

\begin{figure}[H]
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/data_preprocess/data2train/训练数据词句长度统计.pdf}
        \centerline{(1) 数据词句长度统计}
    \end{minipage}%
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/data_preprocess/data2train/训练数据类别统计.pdf}
        \centerline{(2) 训练数据类别统计}
    \end{minipage}
    \caption{训练数据集2特征统计图}\label{fig:figure2}
\end{figure}

\begin{figure}[H]
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/data_preprocess/data2valid/训练数据词句长度统计.pdf}
        \centerline{(1) 数据词句长度统计}
    \end{minipage}%
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/data_preprocess/data2valid/训练数据类别统计.pdf}
        \centerline{(2) 数据类别统计}
    \end{minipage}
    \caption{验证数据集2特征统计图}\label{fig:figure4}
\end{figure}

\begin{figure}[H]
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/data_preprocess/data3train/训练数据词句长度统计.pdf}
        \centerline{(1) 数据词句长度统计}
    \end{minipage}%
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/data_preprocess/data3train/训练数据类别统计.pdf}
        \centerline{(2) 训练数据类别统计}
    \end{minipage}
    \caption{训练数据集3特征统计图}\label{fig:figure2}
\end{figure}

\begin{figure}[H]
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/data_preprocess/data3valid/训练数据词句长度统计.pdf}
        \centerline{(1) 数据词句长度统计}
    \end{minipage}%
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/data_preprocess/data3valid/训练数据类别统计.pdf}
        \centerline{(2) 数据类别统计}
    \end{minipage}
    \caption{验证数据集3特征统计图}\label{fig:figure5}
\end{figure}

从上述5组图片我们可以看出：

(1)数据类别主要集中在$"3"$的类别,比例超过了整个数据集规模的50$\%$,其次是$"2","4"$两个类别，$"1","5"$类别较少，总和不到10$\%$，说明此数据集内评价趋向中等。

(2)词句长度的分布总体呈现短暂升高后递减的趋势，2个词的评价语句最多(超过15$\%$)，绝大部分语句都在1-10个词句之间.

(3)采用不同数据集进行统计，得到的图像和结论却十分接近，这说明每个数据集的完整性和独立性较强，特征较为统一，侧面验证了分割效果良好，为后续操作打下良好基础。

数据预处理的函数是DataSplit类中的data\_preprocess方法。

\newpage
\section{网络的构建}

在本次实验中，我们构建了\textbf{三个不同的神经网络}模型来解决烂番茄电影评论打分这个情感分类的问题，并把结果进行了对比。
\begin{figure}[H]
	\begin{center}
		\includegraphics[scale=0.50]{images/网络构建图.pdf}
		\caption{网络的构建}
		\label{}
	\end{center}
\end{figure}

\subsection{BertNet网络的构建和训练}

我们使用了\textbf{基于BERT预训练模型的神经网络}作为第一个神经网络模型。
BERT模型是谷歌在2018年提出的一个无监督预训练语言模型，它利用了大规模的预料进行了预训练，具有很强的语义理解能力。
相比于其它神经网络模型，BERT有很多优势。[3]
首先，BERT是一种预训练模型，采用了迁移学习的思想，所以无需经过长时间训练就可以在特定的任务上达到相当高的准确率，大大节省了训练时间。
同时，BERT是BERT基于Transformer的双向训练模型，可以很好地实现并行化，有利于使用GPU加速训练过程，其双向结构可以记录上下文信息，使其有更好的性能。
我们使用这个模型进行了10个epoch的训练，模型的最终平均准确率达到了$\mathbf{70.61\%}$。
\subsubsection{Dataset的构建}
我们使用BertDataset类来构建BERT模型所需的Dataset。BertDataset类位于tools目录下的data\_process.py文件中。

BertDataset首先加载预训练好的BERT分词器进行分词。对于每一个数据集中的句子，我们首先按BERT规定的方式进行分词，接着把各单词
映射成它在词典中的位置，最后，我们需要加上句子开始符和结束符等特殊符号，并且记录该句子的标签和注意力掩码。这样，我们就把句子映射成了一个张量。
需要注意的是，为了保证每个句子所对应的张量大小相同，当句子的长度小于最大长度时，不足的位数用0补齐。
对于张量，我们可以直接使用Pytorch提供的TensorDataset类来构建Dataset。

\subsubsection{网络构建}
我们使用BertNet类来构建基于BERT预训练模型的神经网络的结构。BertNet类位于根目录下的nets.py文件内。

网络由BERTModel层和分类器层组成。其中BERTModel负责把Dataset中的句子映射成包含句子语义和上下文意义的张量，
分类器负责把BERTModel层输出的向量进行分类，输出最后预测出的类别。

BERTModel层即BERT预训练模型。它由多个Transformer的encoder部分堆叠而成。本实验中用到的bert-base有12个Transformer的encoder。
Transformer的encoder部分由多头注意力机制、残差连接层等组成。其具体结构如下图所示。

\begin{figure}[H]
	\begin{center}
		\includegraphics[scale=0.55]{images/Bert结构.pdf}
		\caption{BERTModel层的结构}
		\label{1}
	\end{center}
\end{figure}

分类器由3层Linear-ReLU-Dropout结构叠加而成。全连接层Linear和激活函数ReLU共同构成分类器的一层，完成分类任务。
而Dropout层以随机使一部分连接失效的方式减少模型对某一个特性的依赖程度，防止模型过拟合。分类器的结构如下图所示。
\begin{figure}[H]
	\begin{center}
		\includegraphics[scale=0.80]{images/Net1分类器结构.pdf}
		\caption{分类器的结构}
		\label{2}
	\end{center}
\end{figure}

当前向传播时，输入张量依次通过BERTModel层和分类器层的计算，之后输出。

\subsection{FastTextNet网络的构建和训练}

接着，我们使用\textbf{基于GloVe和FastText模型的神经网络}作为第二个神经网络模型。

GloVe模型是一种基于单词与单词的共现矩阵构造的word embedding模型，在2014年由Jeffrey Pennington等人首次提出，该模型借鉴了LSA和Word2Vec模型的优势，并提供多个预训练模型。
在词向量训练模型领域，GloVe模型有许多显著的优势。[4]
首先，GloVe既使用了语料库的全局统计（overall statistics）特征，也使用了局部的上下文特征（即滑动窗口），更加适合情感分析领域。
同时，相比于全局矩阵分解方法，由于GloVe不需要计算那些共现次数为0的词汇，因此，可以极大的减少计算量和数据的存储空间。

FastText是一种Facebook AI Research在16年开源的一个文本分类器，其特点就是Fast，
由于其使用词embedding而非词本身作为特征，使得其在执行标签预测，经典文本任务，能够在保持分类效果的同时，大大缩短训练时间。

我们使用\textbf{GLove+FastText}模型进行了10个epoch的训练，模型的最终平均准确率达到了$\mathbf{51.08\%}$。

\subsubsection{Dataset的构建}

我们使用FastTextDataset类来构建GloVe+FastText模型所需的Dataset。FastTextDataset类位于tools目录下的data\_process.py文件中。

FastTextDataset首先首先通过torchtext.data中的get\_tokenizer方法将每个句子进行分词，
接着下载GloVe预训练好的词典，选择维度为100，这代表每一个词向量都是1x100维的，方便后续运算，
遍历每一个句子，调用glove中的get\_vecs\_by\_tokens方法，将每个句子映射成90x100的二维张量，
因为句子的长度均不超过90，为保证每个句子的张量大小相等，对长度小于90的句子，以若干1x100的张量补齐。

\subsubsection{网络构建}

我们使用FastTextNet类来构建基于GloVe和FastText模型的神经网络的结构。FastTextNet类位于根目录下的nets.py文件内。

网络由Lstm层和文本分类器FastText层组成。
LSTM层负责把单句由GloVe模型生成的90x100维词向量组转换成张量。
文本分类器FastText层负责把LSTM层输出的向量进行分类，输出最后预测出的类别。

LSTM层使用nn.lstm方法，输入维度为100维，由四层叠加而成，采取双向的模式。
文本分类器FastText由2层Linear-BatchNorm-ReLU结构和一个Linear层叠加而成。全连接层Linear，正则函数BatchNorm1d，激活函数ReLU共同构成分类器的一层，完成分类任务。
其中BatchNorm1d层的作用是在深度神经网络训练过程中使得每一层神经网络的输入保持比较标准的正态分布，减少训练中梯度消失，模型难拟合等问题。
文本分类器FastText的结构如下图所示。
\begin{figure}[H]
	\begin{center}
		\includegraphics[scale=0.80]{images/FastText分类器结构.pdf}
		\caption{FastText分类器的结构}
		\label{9}
	\end{center}
\end{figure}

当前向传播时，输入张量依次通过LSTM层和文本分类器FastText层的计算，最后调用nn.flatten方法将连续的维度范围展平为维度为1的张量后输出。


\subsection{Word2Vec\&CNN网络的构建和训练}

我们基于Word2Vec+CNN模型构建了第三个神经网络。
Word2Vec是一款由Google公司开放的训练词向量的工具，其可根据给定的语料库，
通过训练模型将每个词语映射成向量形式，实现词嵌入。
通过词嵌入，我们可以将任意一个句子转化为由若干词语向量构成的张量，即类似于二维张量的形式，
从而便于CNN进行处理。[5]

\subsubsection{Dataset的构建}
我们使用Word2VecDataset类来搭建Word2VecCNN模型所需的Dataset。\\
Word2VecDataset类位于tools目录下的dataprocess.py文件中。

在Word2VecDataset中，我们首先通过torchtext.data中的get\_tokenizer方法将每个句子进行分词操作。
随后将所有分词后的句子所构成的列表作为Word2Vec方法的sentences参数，
得到所有单词对应向量(大小：1x100)的字典。
最后，遍历所有句子，将每个句子映射成90x100的二维张量。为保证每个句子的张量大小相等，且注意到所有句子的长度均不超过90，故而考虑对长度小于90的句子，以若干1x100的张量补齐。

\subsubsection{网络构建}
我们使用Word2VecCNNNet类来构建基于Word2Vec+CNN神经网络的结构。Word2VecCNN类位于根目录下的nets.py文件内。

网络主要由两个卷积层，一个池化层，三个全连接层构成，并使用ReLU激活函数与Dropout调整模型。

第一卷积层设置输入通道数为1，输出通道数为3，卷积核大小为3x3，将16x1x90x100的input输入转化为32x30x30；第二卷积层设置输入通道数为3，输出通道数为6，卷积核大小为3x3，将32x30x30转换为64x10x10；再通过设置池化层stride为2，将64x10x10转化为64x5x5；最后经过三个连接层，输入通道数分别为12384,1200,120,输出通道数分别为1200,120,5，输出最后预测出的类别。

其具体结构大致如下。
\begin{figure}[H]
	\begin{center}
		\includegraphics[scale=0.25]{images/Word2VecCNN结构图.pdf}
		\caption{Word2VecCNN结构图}
		\label{}
	\end{center}
\end{figure}


\newpage
\section{网络的训练}

当网络全部构建完成后，我们就可以开始网络的训练。对于每一个网络，我们依次使用分割好的3个数据集进行训练，并在
cache目录下生成对应的最优网络参数best.pkl和最新网络参数newest.pkl。网络训练的过程如下图所示

\begin{figure}[H]
	\begin{center}
		\includegraphics[scale=0.50]{images/网络训练图.pdf}
		\caption{网络训练}
		\label{3}
	\end{center}
\end{figure}
\begin{figure}[H]
	\begin{center}
		\includegraphics[scale=0.50]{images/网络训练流程图.pdf}
		\caption{训练流程}
		\label{4}
	\end{center}
\end{figure}

\subsection{Dataloader的构建}
在训练前，我们首先需要根据训练集和验证集的Dataset来构建对应的Dataloader。在训练时，网络的输入可从训练集Dataloader中获取；在验证时，网络的输入可从验证集Dataloader中获取。

我们可以直接使用Pytorch中提供的Dataloader类来构建Dataloader。Dataloader接受3个参数，即对应的Dataset、batch选择方法和大小。
需要注意的时，在构建训练集Dataloader时，我们随机地选取batch；而在构建验证集Dataloader时，我们顺序地选取batch。

\subsection{损失函数的选择}

损失函数是用来衡量模型输出和真实值差异的大小的函数。本实验要解决的问题属于多分类问题。
对于这种问题，我们一般采用\textbf{交叉熵损失函数（CrossEntropy Loss）}作为训练的损失函数。
假设有$K$个标签，那么$N$个训练样本的交叉熵计算函数是
$$ Loss=-\frac{1}{N}\sum_{i=0}^{N-1}\sum_{k=0}^{K-1} y_{ik}lnP_{ik} $$
其中，$y_{ik}$表示第$i$个样本的真实标签为$k$，$P_{ik}$表示第$i$个样本预测为第$k$个标签值的概率。

我们可以直接使用Pytorch中提供的CrossEntropyLoss作为损失函数。

\subsection{正则化}

正则化是指在训练中对损失函数附加的一些限制。这些限制可以在一定程度上缓解模型的过拟合现象，从而增强模型的泛化能力。
根据附加的规则，正则化可分成$L_1$正则化和$L_2$正则化等。$L_1$正则化使所有参数的绝对值和尽量小，而$L_2$正则化
使所有参数的平方和尽量小。

在本次实验中，我们使用\textbf{权值衰减（weight decay）}来进行正则化。在Pytorch中，权值衰减可以通过优化器传入的参数
格式进行设置。我们向优化器中传入一个含有参数名称和权值衰减率的字典即可完成权值衰减的设置。

\subsection{优化器的选择}

优化器用来决定模型的参数如何改变。常用的优化器有SGD,Momentum,\\Adam,AdamW等。
在本实验中，我们选择\textbf{Adam作为优化器}。Adam使用自适应学习率和动量梯度下降算法，可以适应本实验中的稀疏梯度，
也可以缓解梯度震荡问题。其更新公式如下：
$$ 
\begin{aligned}
	& m_t=\beta_1 m_{t-1}+(1-\beta_1)g\\
	& v_t=\beta_2 v_{t-1}+(1-\beta_2)g^2\\
	& a_t=a_{t-1}-\frac{lr_t m_t}{\sqrt{v_t}+\epsilon}
\end{aligned}
$$
其中，1式计算梯度的一阶指数平滑值，2式计算梯度平方的一阶指数平滑值，3式计算变量的更新值。

我们可以直接使用Pytorch中提供的AdamW优化器，把weight\_decay设置成0即可。

\subsection{学习率衰减策略}
学习率是优化器梯度下降算法中决定参数如何随当前梯度改变的参数。学习率较小时，模型收敛较慢，模型容易陷入局部最优解中；
学习率较大时，模型可能越过全局最优解，甚至无法收敛。所以，我们有必要选择一个恰当的学习率。一般情况下，在学习初期，
参数是随机初始化的，这时，设置一个较大的学习率有利于模型快速收敛。在学习后期，参数已十分接近最优值，应该设置一个较小的学习率逼近全局最优解。
所以，学习率应随训练轮数而衰减。

在本实验中，除了学习率衰减策略外，我们还使用了\textbf{warm-up机制}。warm-up机制使学习率在训练初期由0快速递增到设置的
最大学习率，接着缓慢衰减。这样，可以使模型在训练初期快速趋于稳定，使得模型收敛速度变得更快，模型效果更佳。

我们可以直接使用Pytorch中提供的get\_linear\_schedule\_with\_warmup函数进行学习率衰减。这个函数使学习率由0线性递增到
最大值，之后线性衰减到0。

\subsection{训练可视化}

在本次实验中，我们使用\textbf{TensorBoard和Matplotlib两种工具}对训练和测试过程进行了可视化。

\subsubsection{训练过程和网络参数的可视化}

为了使训练过程可视化，我们在训练过程中加入了\textbf{TensorBoard可视化模块}。

TensorBoard是TensorFlow中的一个可视化工具。借助于TensorBoard工具，我们可以实时地看到训练准确率、验证准确率
以及模型的参数变化情况。在本实验中，我们在TensorBoard中绘制了训练准确率、验证准确率随epoch的变化折线图，
训练准确率在一个epoch中随batch的变化折线图，以及网络各层参数的分布柱状图。这些图的信息存储在figs目录下。下图是训练过程中的TensorBoard
\begin{figure}[H]
	\begin{center}
		\includegraphics[scale=0.42]{images/TensorBoard.png}
		\caption{训练过程中的TensorBoard}
		\label{}
	\end{center}
\end{figure}

\subsubsection{训练结果的可视化}

同时，为使训练结果更加直观，在本实验中，我们借助了Matplotlib工具对训练的各项结果进行了绘图。
我们绘制了每个数据集的平均训练损失、平均训练准确率、验证准确率随epoch的变化折线图，
训练损失、训练准确率、验证损失随batch的变化折线图；
并绘制了3个数据集合并一起的损失函数值、准确率随epoch的变化折线图。

在结果展示章节中，我们挑选了一部分具有代表性的图进行展示。全部的图存储在figs目录下，可以在figs目录下查看。

\subsection{网络参数存储}

为了方便后续测试和断点续训练，我们在模型训练过程中加入了\textbf{参数存储的功能}。对于用任一数据训练的任一网络，我们存储最新
（newest）和最优（best）的网络参数。这些参数存储在cache目录下。当测试或configs中断点续训练设置成True，且存储参数的文件存在时，我们把参数加载到模型并开始测试或继续训练。

我们可以直接使用Pytorch中提供的torch.save和torch.load函数来进行网络参数的存储和加载。
存储时，我们将网络状态、优化器状态和当前epoch数存储在字典内，接着使用torch.save进行存储。
加载时，我们首先使用torch.load加载，接着使用load\_state\_dict函数将相关参数分别加载到网络和优化器中。
完整的存储加载函数在tools目录下的utils.py文件中。

\newpage
\section{网络测试}

网络训练结束后，我们分别使用三个网络的验证集进行网络测试求解。在训练过程中，验证集的所有数据均未输入过网络进行训练，
这保证了网络测试可以准确地反映模型的泛化能力。
我们将网络预测的分类与真值比较，计算网络的测试准确率，把三个数据集的准确率取平均后得到三个网络的平均准确率。
最后我们进行可视化处理，绘制出每个网络在三个数据集上的准确率以及平均准确率的柱状图。网络测试文件为test.py文件。

\subsection{测试流程}
对于每个网络，我们均进行三遍测试，测试流程和训练流程大体相同。每遍测试的大致过程如下：

\begin{enumerate}
	\item 数据处理：和网络训练时相同，我们首先使用相应的网络方法构建相应网络的Dataset，再直接使用Pytorch中提供的Dataloader类来构建Dataloader。
	\item 网络构建：我们构建和训练时完全相同的网络进行训练。
	\item 网络参数与模型参数获取：我们从config.py文件中获取相应网络的网络参数，并从cache文件夹中获取由网络训练模块训练产生的模型参数。
	\item 预测：把验证集输入网络进行测试，获取网络输出的预测结果。
	\item 计算准确率：将预测结果与真实值比对，计算准确率。
\end{enumerate}

\subsection{测试结果及可视化}
经过测试，\textbf{基于BERT预训练模型的网络的预测准确率是$\mathbf{70.61\%}$，FastTextNet网络的预测准确率是$\mathbf{51.08\%}$，Word2Vec\&CNN网络的预测准确率是$\mathbf{51.09\%}$}。

我们采用Matplotlib封装的\textbf{Seaborn绘图工具箱}对测试结果进行可视化，将三个网络的三次测试准确率以柱状图形式作于一张图中。
我们将相应的图形信息存储在figs目录下的test\_result\_figs文件中；相应的数据信息存储在figs目录下的info\_for\_figs文件中。
结果的图片可以在下文结果展示中查看。

\newpage
\section{结果展示}

在这一小节，我们将对程序运行的结果进行展示。

我们将3种模型训练后的对三个数据集网络测试准确率进行了可视化呈现，如下图所示：

\begin{figure}[H]
	\begin{center}
		\includegraphics[scale=0.42]{../figs/test_result_figs/三个网络测试准确率图.pdf}
		\caption{三个网络测试准确率图}
		\label{}
	\end{center}
\end{figure}

其中基于BERT预训练模型的神经网络模型的最终平均预测准确率达到了$\mathbf{70.61\%}$，
基于GloVe和FastText模型的神经网络模型的最终平均预测准确率达到了$\mathbf{51.08\%}$，
基于Word2Vec和CNN的神经网络模型的最终平均预测准确率达到了$\mathbf{51.09\%}$，
可以看出BERT预训练模型的训练效果更好。在准确率上大幅领先其他两种模型。
而其他两种模型训练速度显著快于BERT模型，可应用于对准确率要求不高的情形。

我们还绘制了3个模型的准确率、损失函数值在训练和验证时的变化情况。
从上到下依次展示各模型验证时的准确率、损失函数变化图，训练时准确率、损失函数随每个epoch的变化图，训练时准确率、损失函数随每个batch的变化图。
绘制的图像如下所示：

\begin{figure}[H]
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/bert_net/all_data/准确率变化图.pdf}
        \centerline{(1) BertNet准确率变化图}
    \end{minipage}%
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/bert_net/all_data/损失函数值变化图.pdf}
        \centerline{(2) BertNet损失函数值变化图}
    \end{minipage}
    \caption{BertNet模型效果图}\label{fig:figure9}
\end{figure}

\begin{figure}[H]
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/bert_net/all_data/平均训练准确率变化图.pdf}
        \centerline{(1) BertNet平均训练准确率变化图}
    \end{minipage}%
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/bert_net/all_data/平均训练损失变化图.pdf}
        \centerline{(2) BertNet平均训练损失变化图}
    \end{minipage}
    \caption{BertNet训练效果图}\label{fig:figure10}
\end{figure}

\begin{figure}[H]
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/bert_net/all_data/训练准确率变化图.pdf}
        \centerline{(1) BertNet训练准确率变化图}
    \end{minipage}%
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/bert_net/all_data/训练损失变化图.pdf}
        \centerline{(2) BertNet训练损失变化图}
    \end{minipage}
    \caption{BertNet训练效果图}\label{fig:figure11}
\end{figure}

\begin{figure}[H]
\begin{minipage}[t]{0.5\linewidth}
    \centering
    \includegraphics[width=\textwidth]{../figs/fast_text_net/all_data/准确率变化图.pdf}
    \centerline{(1) FastTextNet准确率变化图}
\end{minipage}%
\begin{minipage}[t]{0.5\linewidth}
    \centering
    \includegraphics[width=\textwidth]{../figs/fast_text_net/all_data/损失函数值变化图.pdf}
    \centerline{(2) FastTextNet损失函数值变化图}
\end{minipage}
\caption{FastTextNet模型效果图}\label{fig:figure13}
\end{figure}

\begin{figure}[H]
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/fast_text_net/all_data/平均训练准确率变化图.pdf}
        \centerline{(1) FastTextNet平均训练准确率变化图}
    \end{minipage}%
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/fast_text_net/all_data/平均训练损失变化图.pdf}
        \centerline{(2) FastTextNet平均训练损失变化图}
    \end{minipage}
    \caption{FastTextNet训练效果图}\label{fig:figure14}
\end{figure}

\begin{figure}[H]
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/fast_text_net/all_data/训练准确率变化图.pdf}
        \centerline{(1) FastTextNet训练准确率变化图}
    \end{minipage}%
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/fast_text_net/all_data/训练损失变化图.pdf}
        \centerline{(2) FastTextNet训练损失变化图}
    \end{minipage}
    \caption{FastTextNet训练效果图}\label{fig:figure15}
\end{figure}

\begin{figure}[H]
\begin{minipage}[t]{0.5\linewidth}
    \centering
    \includegraphics[width=\textwidth]{../figs/word2vec_cnn_net/all_data/准确率变化图.pdf}
    \centerline{(1) Word2Vec \& CNN准确率变化图}
\end{minipage}%
\begin{minipage}[t]{0.5\linewidth}
    \centering
    \includegraphics[width=\textwidth]{../figs/word2vec_cnn_net/all_data/损失函数值变化图.pdf}
    \centerline{(2) Word2Vec \& CNN损失函数值变化图}
\end{minipage}
\caption{Word2Vec \& CNN模型效果图}\label{fig:figure17}
\end{figure}

\begin{figure}[H]
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/word2vec_cnn_net/all_data/平均训练准确率变化图.pdf}
        \centerline{(1) Word2Vec \& CNN平均训练准确率变化图}
    \end{minipage}%
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/word2vec_cnn_net/all_data/平均训练损失变化图.pdf}
        \centerline{(2) Word2Vec \& CNN平均训练损失变化图}
    \end{minipage}
    \caption{Word2Vec \& CNN训练效果图}\label{fig:figure18}
\end{figure}

\begin{figure}[H]
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/word2vec_cnn_net/all_data/训练准确率变化图.pdf}
        \centerline{(1) FastTextNet训练准确率变化图}
    \end{minipage}%
    \begin{minipage}[t]{0.5\linewidth}
        \centering
        \includegraphics[width=\textwidth]{../figs/word2vec_cnn_net/all_data/训练损失变化图.pdf}
        \centerline{(2) FastTextNet训练损失变化图}
    \end{minipage}
    \caption{Word2Vec \& CNN训练效果图}\label{fig:figure19}
\end{figure}

\section{实验总结}

\textbf{崔昊阳}：

通过这次实验，我使用了多种神经网络模型来解决实际问题。在实现模型的过程中，综合使用了Pytorch,Tensorflow,Matplotlib,Seaborn等多种常用Python第三方库，
这大大提升了我的Python编程能力，为后续继续选修机器学习相关课程打下了良好的基础。

\textbf{林光明}：

本次实验是我第一次以python作为编程语言，大量使用python库实现具有一定具体功能的程序的实验，
也让我第一次接触人工智能和机器学习算法。
同时，在本次实验中，我学习到了NLP这一知识，对人工智能领域有了初次的探索，
在实验期间，逐一克服各种问题让我对大数据处理、对AI有着更深的兴趣，希望日后能够继续学习，从中磨练自己！

\textbf{罗理恒}：

本次课程是我第一次系统地接触和学习python深度学习的算法和应用，大作业从审题到分工，
从处理原始数据集到搭建自己的网络，从优化调参到撰写实验报告。
其作始也简，其将毕也其必巨。在对深度学习的不断探索中，我了解了NLP等基础任务，GLoVe，Bert等分词模型，
LSTM，FastText等分类器，当程序开始自动运行，当网络一遍遍被训练，我的心情是激动的。
代码是一行行编译的，报告是一行行撰写的，人工智能领域的学习从来没有捷径，只有不断试错，不断优化，
才有最终测试结果的喜悦。希望我在未来的学习中也能像执行深度学习框架步骤一样，在损失中成长，在优化中磨砺！


\section{参考文献}
[1]陈龙,管子玉,何金红,彭进业.情感分类研究进展[J].计算机研究与发展,2017,54(06):1150-1170. 

[2]谢润忠,李烨.基于BERT和双通道注意力的文本情感分类模型[J].数据采集与处理,2020,35(04):642-652.DOI:10.16337/j.1004-9037.2020.04.005.

[3]周燕.基于GloVe模型和注意力机制Bi-LSTM的文本分类方法[J].电子测量技术,2022,45(07):42-47.DOI:10.19651/j.cnki.emt.2107678.

[4]刘思琴,冯胥睿瑞.基于BERT的文本情感分析[J].信息安全研究,2020,6\\(03):220-227.  

[5]蔡慧苹,王丽丹,段书凯.基于word embedding和CNN的情感分类模型[J].计算机应用研究,2016,33(10):2902-2905+2909.


\end{document}
